import { 
  createSlice,
  createAsyncThunk,
  createEntityAdapter,
  createSelector,
  createAction,
  isAnyOf 
} from "@reduxjs/toolkit";

import { client } from "../../api/client";
import { forceGenerateNotifications } from '../../api/server';
import apiSlice from '../api/apiSlice';



const notificationsReceived = createAction(
  "notifications/notificationsReceived"
);

// const notificationsAdapter = createEntityAdapter({
//   sortComparer: (a, b) => b.date.localeCompare(a.date),
// });

const notificationsAdapter = createEntityAdapter();



export const fetchNotifications = createAsyncThunk(
  "notifications/fetchNotifications",
  async (_, { getState }) => {
    const allNotifications = selectAllNotifications(getState());
    const [latestNotification] = allNotifications;
    const latestTimestamp = latestNotification ? latestNotification.date : "";
    const response = await client.get(
      `/fakeApi/notifications?since=${latestTimestamp}`
    );
    return response.data;
  }
);

const notificationsSlice = createSlice({
  name: "notifications",
  initialState: notificationsAdapter.getInitialState(),
  reducers: {
    allNotificationsRead(state, action) {
      // state.forEach((notification) => {
      //   notification.read = true;
      // });

      Object.values(state.entities).forEach((notification) => {
        notification.read = true;
      });
    },
  },
//   extraReducers: {
//     [fetchNotifications.fulfilled]: (state, action) => {
//       state.push(...action.payload);
//       // 以最新的优先排序
//       state.sort((a, b) => b.date.localeCompare(a.date));
//     },
//   },
  extraReducers(builder) {
    // builder.addCase(fetchNotifications.fulfilled, (state, action) => {
    //     // state.forEach((notification) => {
    //     //   // Any notifications we've read are no longer new
    //     //   notification.isNew = !notification.read;
    //     // });
    //     // state.push(...action.payload);
    //     // // 以最新的优先排序
    //     // state.sort((a, b) => b.date.localeCompare(a.date));


    //     Object.values(state.entities).forEach((notification) => {
    //       // Any notifications we've read are no longer new
    //       notification.isNew = !notification.read;
    //     });
    //     notificationsAdapter.upsertMany(state, action.payload);
    // })

    builder.addMatcher(matchNotificationsReceived, (state, action) => {
      // 添加客户端元数据以跟踪新通知
      const notificationsMetadata = action.payload.map((notification) => ({
        id: notification.id,
        read: false,
        isNew: true,
      }));

      Object.values(state.entities).forEach((notification) => {
        // 我们读过的任何通知都不再是新的
        notification.isNew = !notification.read;
      });

      notificationsAdapter.upsertMany(state, notificationsMetadata);
    });
  }
});

export default notificationsSlice.reducer;

//export const selectAllNotifications = (state) => state.notifications;

export const { 
  selectAll: selectAllNotifications, 
  selectAll: selectNotificationsMetadata,
  selectEntities: selectMetadataEntities,
} = notificationsAdapter.getSelectors((state) => state.notifications);

export const { allNotificationsRead } = notificationsSlice.actions;

// RTK 查询高级模式
export const extendedApi = apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    getNotifications: builder.query({
      query: () => "/notifications",
      // 
      async onCacheEntryAdded(arg,{updateCachedData,cacheDataLoaded,cacheEntryRemoved,dispatch}) {
        // cacheDataLoaded 在此订阅的初始化数据添加到存储时解析
        // 当缓存订阅开始时创建一个 websocket 连接
        const ws = new WebSocket("ws://localhost");
        try {
          // 等待初始查询解决后继续
          await cacheDataLoaded;
          // 用收到的消息更新我们的查询结果

          const listener = (event) => {
            const message = JSON.parse(event.data);
            switch (message.type) {
              case "notifications": {
                updateCachedData((draft) => {
                  // 插入所有从 websocket 接收到的通知
                  // 进入现有的 RTKQ 缓存数组
                  draft.push(...message.payload);
                  draft.sort((a, b) => b.date.localeCompare(a.date));
                });
                // dispatch 一个额外的 action，以便我们可以跟踪 “read” state
                dispatch(notificationsReceived(message.payload));
                break;
              }
              default:
                break;
            }
          }
          ws.addEventListener("message", listener);
        } catch {

        }

        // cacheEntryRemoved 将在缓存订阅不在活动时解析
        await cacheEntryRemoved;
        // 一旦 `cacheEntryRemoved` 承诺解决，执行清理步骤
        ws.close();
      }
    })
  })
})

const matchNotificationsReceived = isAnyOf(
  notificationsReceived,
  extendedApi.endpoints.getNotifications.matchFulfilled
);

export const { useGetNotificationsQuery } = extendedApi;


export const selectNotificationsResult = extendedApi.endpoints.getNotifications.select();

const selectNotificationsData = createSelector(
  selectNotificationsResult,
  (notificationsResult) => notificationsResult.data ?? []
);


export const fetchNotificationsWebsocket = () => (dispatch, getState) => {
  console.log('fetchNotificationsWebsocket')
  const allNotifications = selectNotificationsData(getState());
  const [latestNotification] = allNotifications;
  const latestTimestamp = latestNotification?.date ?? "";
  // 对模拟服务器的调用进行硬编码，以通过 websocket 模拟服务器推送场景
  // 模拟将数据推送到客户端
  forceGenerateNotifications(latestTimestamp);
};